iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 13
0
Modern Web

寫React的那些事系列 第 13

React Day13 - TODOS Demo(1)

  • 分享至 

  • xImage
  •  

今天終於要進入React實戰階段,學習語言除了一開始練習建立Hello World,通常完整功能就是實作一套CRUD(Create、Read、Update、Delete),而todo list是最簡易的一個demo練習。是,就是走老套路線。

Step1


首先,使用CLI npm指令,先在專案folder根目錄下建立package.json:

npm init -y

再來安裝,專案會用到的相關套件:

// --save 安裝會用到的套件
// --save-dev 安裝開發會用到的套件

// webpack
npm install webpack --save-dev

// webpack hot reload 相關
npm install express webpack-dev-server webpack-dev-middleware webpack-hot-middleware --save-dev

// react 相關
npm install react react-dom --save

// babel 相關
npm install babel-core babel-loader babel-preset-es2015 babel-preset-react --save-dev

Step2


建立webpack config檔案:

touch webpack.config.js

設定config內容,使用babel-loader處理js檔案,並設置plugins:

const webpack = require('webpack');
const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.join(__dirname, 'build'),
        filename: 'bundle.[hash].js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel',
                query: {
                    presets: ['es2015', 'react']
                }
            }
        ]
    },
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin()
    ],
    resolve: {
        extensions: ['', '.js']
    }
};

Step3


建立server.js來啟用hot reload開發環境,重點在entry必須加上webpack-hot-middleware設定,與output.publicPath指定localhost:

const path = require('path');
const webpack = require('webpack');
const express = require('express');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');

// change webconfig for hot reload
const config = require('./webpack.config');
const webpackConfig = Object.create(config);
webpackConfig.entry = [
    'webpack-hot-middleware/client?reload=true',
    './src/index.js'
];
webpackConfig.output = {
    path: path.join(__dirname, 'build'),
    filename: 'bundle.js',
    publicPath: 'http://localhost:8080/'
};

// express
const app = express();
const compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, {
  publicPath: webpackConfig.output.publicPath,
    noInfo: true,
    stats: {
        colors: true
    }
}));
app.use(webpackHotMiddleware(compiler));
app.get('*', function(req, res) {
    // use index.html
    res.sendFile(__dirname + '/index.html');
});

// listen port
app.listen(8080, function(error) {
    if (error) {
        console.error(error);
    } else {
        console.info('==> ?  Listening on port %s. Open up http://localhost:%s/ in your browser.', 8080, 8080);
    }
});

在server.js建立時,我們會指定render一個index.html,裡面需要有一個div,讓我們產生element可以append,然後還需要把bundle後的js放入:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>ReactTodos</title>
</head>
<body>
    <div id="main"></div>
    <script src="bundle.js"></script>
</body>
</html>

之後要啟用開發環境時,只需要執行:

node server.js

或是在package.json的script加上快捷指令:

"scripts": {
  "dev": "node server.js"
}

然後,CLI執行:

npm run dev

Step4


建立網站entry檔案 index.js:

  • 用ReactDOM.render,把網站根元件App append到div上。
  • 使用ES6的import來把外部檔案載入,可以參考ES6 import
  • 如果import的是package,直接import from套件,如果是自己開發的檔案,則需加上./來表示當前目錄。

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './app';

ReactDOM.render(
    <App />,
    document.getElementById('main')
);

Step5


按照我們最後想呈現的結果,來切割元件:

Layout架構 (root component)
├── React Todo list標題 (h1)
├── Add todo表單 (TodoAdd component)
└── Todo list元件 (TodoList component)
  ├── Table 標題  (thead)
  └── Table 內容  (tbody)
    └── Todo item元件 (TodoItem component)

從上面架構來看,我們會有app.js、TodoAdd.js、TodoList.js、TodoItem.js四個檔案,除了app.js是根元件,因為另外三個都是屬於components,可以把他們收在一個components的資料夾,以便之後檔案越來越多方便管理,如果component又可以用不同單元來區分,可以再細分成每個單元的資料夾,或是用功能區分,把同功能的js檔放一起。但這邊components還很單純,所以我們先放一個components的資料夾就可以了。

app.js

  • 建立App元件,extends React.Component,這邊先用import列出{ Component },它就是我們之前常用的React.Component,只是用ES6 import語法,先把他列出來。
  • 記得元件要用一個element包住,每個component只會有一個根元件。
  • 最後,記得export default App,這樣我們在index.js才可以import from App。
import React, { Component } from 'react';
import TodoList from './components/TodoList';
import TodoAdd from './components/TodoAdd';

class App extends Component {
    render() {
        return (
            <div>
                <h1>React Todo List</h1>
                <TodoAdd />
                <TodoList />
            </div>
        );
    }
}

export default App;

TodoAdd.js

  • 這邊先把新增todo的元件列出來,因為CRUD要有create,之後我們會再來加強這個元件的功能。
import React, { Component } from 'react';

class TodoAdd extends Component {
    render() {
        return (
            <div>
                <input type="text" />
                <button>Create</button>
            </div>
        );
    }
}

export default TodoAdd;

TodoList.js

  • List的部分,也可以把<thead>切出來,但因為這部分我們不需要reuse,他也屬於list的一部分,所以這邊只把item切出來。
import React, { Component } from 'react';
import TodoItem from './TodoItem';

class TodoList extends Component {
    render() {
        return (
            <table>
                <thead>
                    <tr>
                        <th>Todo</th>
                        <th>Action</th>
                    </tr>
                </thead>
                <tbody>
                    <TodoItem />
                </tbody>
            </table>
        );
    }
}

export default TodoList;

TodoItem.js

  • item是之後會reuse的部分,每個todo都是一個TodoItem。
import React, { Component } from 'react';

class TodoItem extends Component {
    render() {
        return (
            <tr>
                <td>Finish today</td>
                <td>
                    <button>Edit</button>
                    <button>Delete</button>
                </td>
            </tr>
        );
    }
}

export default TodoItem;

設定完上面的檔案後,執行:

npm run dev

就可以在http://localhost:8080/看到目前的網站了,不過~我們現在還沒有加上state和props,還有點難感受到整個完整的資料流,但已經可以稍微看到拆分元件的好處,簡化了程式碼,依照功能把不同的component拆開,並且用JSX的架構很直覺可以知道這個component會呈現的樣子。

通常會看Layout來切割元件,從視覺去思考,然後也會把許多地方共用到的component切出來,可以參考官網這篇切分元件的方式,或是分久了就會有fu,比較知道怎麼拆分。

今天的檔案已經放在Git上,之後還會陸續commit,所以我把目前的階段標成v1.0,第一次使用git tag來release,算是寫文章的學習,覺得讚!


上一篇
React Day12 - Babel介紹
下一篇
React Day14 - TODOS Demo(2)
系列文
寫React的那些事31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言